<template>
  <!-- 使用 Vant Popover 组件 -->
  <van-popover
    v-model:show="isVisible"
    :placement="adjustedPlacement"
    :overlay="false"
    :teleport="teleportTarget"
    :offset="offset"
    v-bind="$attrs"
    @open="onOpen"
    @close="onClose"
    @opened="onOpened"
    @closed="onClosed"
  >
    <!-- 自定义 reference 插槽 -->
    <template #reference>
      <div
        ref="referenceElement"
        class="popover-reference"
        :style="referenceStyle"
        @click.stop="togglePopover"
      >
        <slot name="reference" />
      </div>
    </template>

    <!-- 自定义内容插槽 -->
    <div
      ref="popoverContent"
      class="popover-content"
      :class="contentClass"
      :style="contentStyle"
    >
      <slot />
    </div>
  </van-popover>
</template>

<script setup lang="ts">
import {
  ref,
  computed,
  watch,
  onMounted,
  onBeforeUnmount,
  nextTick
} from "vue";
import { PopoverPlacement } from "vant";
import { useScrollLock } from "@vueuse/core";

// 定义组件属性
const props = withDefaults(
  defineProps<{
    // 初始展示位置
    placement?: PopoverPlacement;
    // 是否默认显示
    defaultVisible?: boolean;
    // 距离触发元素的偏移量
    offset?: [number, number];
    // 内容容器自定义类名
    contentClass?: string;
    // 内容容器自定义样式
    contentStyle?: Record<string, string>;
    // reference 容器自定义样式
    referenceStyle?: Record<string, string>;
    // 是否启用位置自适应
    autoAdjust?: boolean;
  }>(),
  {
    placement: "bottom",
    defaultVisible: false,
    offset: 4,
    contentClass: "",
    contentStyle: () => ({}),
    referenceStyle: () => ({}),
    autoAdjust: true
  }
);

// 定义组件事件
const emit = defineEmits<{
  (e: "update:visible", visible: boolean): void;
  (e: "open"): void;
  (e: "opened"): void; // 添加完全打开事件
  (e: "close"): void;
  (e: "closed"): void; // 添加完全关闭事件
  (e: "placement-change", placement: PopoverPlacement): void; // 添加位置变化事件
}>();

// 当前 Popover 是否可见
const isVisible = ref(props.defaultVisible);

// 存储所有打开的 Popover 实例
const openPopovers = new Set<symbol>();

// 当前实例的唯一标识
const instanceId = Symbol("popover-instance");

// 内容元素和 reference 元素的引用
const popoverContent = ref<HTMLElement | null>(null);
const referenceElement = ref<HTMLElement | null>(null);

// 计算调整后的展示位置（确保内容不超出屏幕）
const adjustedPlacement = ref<PopoverPlacement>(props.placement);

// 滚动锁定控制
const isLocked = useScrollLock(document.body);

// 设置 teleport 目标（默认为 body）
const teleportTarget = computed(() => {
  return document.body;
});

// 监听可见状态变化
watch(isVisible, newValue => {
  if (newValue) {
    // 打开时关闭其他所有 Popover
    closeOtherPopovers();

    // 添加到打开的 Popover 集合
    openPopovers.add(instanceId);

    // 锁定页面滚动
    isLocked.value = true;

    // 触发打开事件
    emit("open");
  } else {
    // 从集合中移除
    openPopovers.delete(instanceId);

    // 如果没有打开的 Popover，解锁滚动
    if (openPopovers.size === 0) {
      isLocked.value = false;
    }

    // 触发关闭事件
    emit("close");
  }

  // 更新外部绑定值
  emit("update:visible", newValue);
});

// 切换 Popover 状态
const togglePopover = () => {
  isVisible.value = !isVisible.value;
};

// 关闭其他所有 Popover
const closeOtherPopovers = () => {
  for (const id of openPopovers) {
    if (id !== instanceId) {
      // 触发关闭事件（实际关闭操作由各个实例自己处理）
      openPopovers.delete(id);
    }
  }
};

// 打开 Popover 时调整位置
const onOpen = () => {
  emit("open");
  nextTick(() => {
    if (popoverContent.value && referenceElement.value && props.autoAdjust) {
      // 检查内容是否超出屏幕，并调整位置
      adjustPosition();
    }
  });
};

// Popover 完全打开时
const onOpened = () => {
  emit("opened");
};

// 关闭 Popover 时
const onClose = () => {
  emit("close");
};

// Popover 完全关闭时
const onClosed = () => {
  emit("closed");
  // 重置位置为初始值
  adjustedPlacement.value = props.placement;
};

// 调整 Popover 位置（确保在屏幕内）
const adjustPosition = () => {
  if (!popoverContent.value || !referenceElement.value) return;

  const contentRect = popoverContent.value.getBoundingClientRect();
  const referenceRect = referenceElement.value.getBoundingClientRect();
  const windowWidth = window.innerWidth;
  const windowHeight = window.innerHeight;

  // 计算可用空间
  const spaceAbove = referenceRect.top;
  const spaceBelow = windowHeight - referenceRect.bottom;
  const spaceLeft = referenceRect.left;
  const spaceRight = windowWidth - referenceRect.right;

  // 计算内容尺寸
  const contentHeight = contentRect.height;
  const contentWidth = contentRect.width;

  // 根据当前位置和可用空间调整位置
  let newPlacement = props.placement;

  // 处理垂直方向
  if (props.placement.includes("bottom")) {
    if (spaceBelow < contentHeight && spaceAbove > contentHeight) {
      newPlacement = newPlacement.replace("bottom", "top") as PopoverPlacement;
    }
  } else if (props.placement.includes("top")) {
    if (spaceAbove < contentHeight && spaceBelow > contentHeight) {
      newPlacement = newPlacement.replace("top", "bottom") as PopoverPlacement;
    }
  }

  // 处理水平方向
  if (props.placement.includes("left")) {
    if (spaceLeft < contentWidth && spaceRight > contentWidth) {
      newPlacement = newPlacement.replace("left", "right") as PopoverPlacement;
    }
  } else if (props.placement.includes("right")) {
    if (spaceRight < contentWidth && spaceLeft > contentWidth) {
      newPlacement = newPlacement.replace("right", "left") as PopoverPlacement;
    }
  }

  // 处理中心位置
  if (props.placement.includes("center")) {
    if (spaceBelow < contentHeight && spaceAbove > contentHeight) {
      newPlacement = newPlacement.replace("bottom", "top") as PopoverPlacement;
    } else if (spaceAbove < contentHeight && spaceBelow > contentHeight) {
      newPlacement = newPlacement.replace("top", "bottom") as PopoverPlacement;
    }
  }

  // 如果位置需要调整
  if (newPlacement !== adjustedPlacement.value) {
    adjustedPlacement.value = newPlacement;
    emit("placement-change", newPlacement);
  }
};

// 点击页面其他地方关闭 Popover
const handleOutsideClick = (event: MouseEvent) => {
  if (
    isVisible.value &&
    referenceElement.value &&
    !referenceElement.value.contains(event.target as Node) &&
    popoverContent.value &&
    !popoverContent.value.contains(event.target as Node)
  ) {
    isVisible.value = false;
  }
};

// 处理窗口大小变化
const handleResize = () => {
  if (isVisible.value && props.autoAdjust) {
    adjustPosition();
  }
};

// 组件挂载时添加点击事件监听
onMounted(() => {
  document.addEventListener("click", handleOutsideClick);
  window.addEventListener("resize", handleResize);
});

// 组件卸载前清理
onBeforeUnmount(() => {
  document.removeEventListener("click", handleOutsideClick);
  window.removeEventListener("resize", handleResize);
  openPopovers.delete(instanceId);

  // 如果当前实例是最后一个打开的，解锁滚动
  if (openPopovers.size === 0) {
    isLocked.value = false;
  }
});

// 暴露方法供外部调用
defineExpose({
  open: () => {
    isVisible.value = true;
    return isVisible.value;
  },
  close: () => {
    isVisible.value = false;
    return isVisible.value;
  },
  toggle: togglePopover
});
</script>

<style scoped>
/* 基础样式 */
.popover-reference {
  display: inline-block;
  cursor: pointer;
}

.popover-content {
  max-width: 300px;
  padding: 5px;
  box-sizing: border-box;
  background-color: white;
  border-radius: 8px;
  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.15);
  max-height: 60vh;
  overflow-y: auto;
}

/* 滚动条样式 */
.popover-content::-webkit-scrollbar {
  width: 6px;
}

.popover-content::-webkit-scrollbar-track {
  background: #f1f1f1;
  border-radius: 10px;
}

.popover-content::-webkit-scrollbar-thumb {
  background: #888;
  border-radius: 10px;
}

.popover-content::-webkit-scrollbar-thumb:hover {
  background: #555;
}
</style>
